import {any} from "./logic"
/**
 * 为字符串生成哈希
 * @method
 * @param {string} str 转换为哈希值的字符串
 * @param {number} seed 哈希种子
 * @return {number} 
 */
function stringHash(str, seed = 0) {
    let hash = seed;
    if (str.length === 0) return hash;
    for (let i = 0; i < str.length; i++) {
        let chr = str.charCodeAt(i);
        hash = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
    }
    return hash;
}
/**
 * 为object生成哈希
 * @method
 * @param {Object} object 转换为哈希值的object
 * @param {number} seed 哈希种子
 * @return {number} 
 */
function objectHash(object, seed = 0) {
    let str = JSON.stringify(object);
    return stringHash(str, seed);
}
/**
 * 生成GUID
 * @method
 * @param {string} tag 自定义标签，作为前缀添加至id对应的每一位前
 * @return {string} 生成的GUID
 */
function guid(tag = "") {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return tag + v.toString(16);
    });
}
/**
 * 根据id生成0-1范围内颜色值
 * @method
 * @param {number} index 用于生成颜色值的id
 * @return {Float32Array} 0-1范围的rgb颜色数组
 */
function gIdColor(index) {
    let hex = Math.floor( index );
    let r = ( hex >> 16 & 255 ) / 255;
    let g = ( hex >> 8 & 255 ) / 255;
    let b = ( hex & 255 ) / 255;
    return [r,g,b];

}
/**
 * 将颜色值转换为id
 * @method
 * @param {Array} color rgb颜色数组
 * @return {Float32Array} 转换后的id值
 */
function color2Id(color) {
    return  ((color[ 0 ]) << 16 ) | ( (color[ 1 ]) << 8 ) | ( color[ 2 ])

}
/**
 * 为数组中每个参数调用函数，全部调用结束后对所有处理结果执行回调
 * @method
 * @param {Array} array 参数数组
 * @param {Function} fn 执行函数, 接收两个参数: 
 * 1. 待处理数据
 * 2. cb回调，其中cb回调接收两个参数：
 *      err: 抛出的异常
 *      result: 数据处理结果
 * @param {Function} callback 回调函数, 接收两个参数：
 * err: 调用函数产生的异常
 * results: 所有参数被函数调用后产生的结果数组
 */
function asyncAll(array, fn, callback) {
    if (!array.length) { return callback(null, []); }
    let count = array.length;
    const results = new Array(array.length);
    let error = null;
    array.forEach((item, i) => {
        fn(item, (err, result) => {
            if (err) {
                error = err;
            }
            results[i] = result;
            if (--count === 0) {
                callback(err, results);
            }
        });
    });
}
/**
 * 将源对象的属性混合至目标对象上
 * @method
 * @param {Object} dest 目标对象
 * @param {Object} sources 源对象
 * @return {Object}
 */
function mix(dest, sources) {
    if (!dest) {
        dest = {};
    }
    for (let key in sources) {
        dest[key] = sources[key];
    }
    return dest;
}
/**
 * 在命名空间中创建dom元素
 * @method
 * @param {string} name 要创建的dom元素名称
 * @return {HTMLElement} 创建的dom元素
 */
function createElementNS(name) {

    return document.createElementNS('http://www.w3.org/1999/xhtml', name);

}
/**
 * 判断输入的参数值是否非空
 * @method
 * @param {*} text 输入的参数值
 * @return {Boolean} 参数值是否不为空
 */
function isNotBlank(text) {
    if (text === undefined || text == null) {
        return false
    }
    return true
}
function isBlank(text) {
    if (text === undefined || text == null) {
        return true
    }else{
      return false
    }
}
/**
 * 判断通道是否true.
 * @method
 * @param {*} channel 通道号
 * @param {*} mask 掩码
 * @return {Boolean} 通道是否true。
 */
function test(channel,mask){ //判断通道是否true
    return ( mask & ( 1 << channel | 0 ) ) !== 0;
}
/**
 * 获取设备像素比
 * @method
 * @return {number} 设备像素比。
 */
function getDevicePixelRatio(){
    return any(window.devicePixelRatio,1)
}
/**
 * canvas大小自适应，返回自适应后的结果。
 * @method
 * @param {*} canvas 画布canvas
 * @return {Array.<number>} canvas自适应后的宽高[width, height]
 */
function adjustCanvas(canvas){
    const rect = canvas.getBoundingClientRect();
    const w = rect.width || canvas.clientWidth || canvas.offsetWidth || 0;
    const h = rect.height || canvas.clientHeight || canvas.offsetHeight || 0;
    const ratio=getDevicePixelRatio();
    if(w!=0&&h!=0){
    canvas.width = w *ratio;
    canvas.height = h *ratio;
    }
    return [canvas.width,canvas.height];
} 
/**
 * 获取鼠标在当前设备像素比下的点击位置。
 * @method
 * @param {*} event 事件对象
 * @return {Array.<number>} 鼠标点击位置[x, y]
 */
function getEventPos(event){
    let ratio=getDevicePixelRatio();
    return [event.offsetX*ratio,event.offsetY*ratio];
}
function randomString(e) {    
  e = e || 32;
  var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
  a = t.length,
  n = "";
  for (let i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));
  return n
}
function getGPUType(typeArray) {
  let componentType="uint16"
  const TypedArrayName = typeArray.constructor.name;
    switch (TypedArrayName) {
      case "Uint16Array":
        componentType="uint16"
        break;
      case "Uint32Array":
        componentType="uint32"
        break;
      case "Uint8Array":
        componentType="uint8"
        break;
      default:
        break;
    }
  return componentType
}
function buildFlatArray(group, level = 0) {
    let flatArray = [];
    group.forEach(node => {
        flatArray.push({ ...node, level: level });
        if (Array.isArray(node.children)) {
            flatArray = [...flatArray, ...this.buildFlatArray(node.children, level + 1)];
        }
    });
    return flatArray;
}
function getId(object){
    if(typeof object==="string"){
        return object
    }else{
        return object.id;
    }
}
function checkTypedArrayType(typedArray) {
    const typedArrayTypes = [
        Int8Array,
        Uint8Array,
        Uint8ClampedArray,
        Int16Array,
        Uint16Array,
        Int32Array,
        Uint32Array,
        Float32Array,
        Float64Array,
        BigInt64Array,
        BigUint64Array
    ];
    const checked = typedArrayTypes.filter(ta => typedArray.constructor === ta);
    return checked.length && checked[0].name.toLowerCase().slice(0, checked[0].name.length - 5) || null;
}
const VertexFormat=["","","x2","x3","x4"]
function setUnion(setA, setB) {
    const _union = new Set(setA);
    for (const elem of setB) {
      _union.add(elem);
    }
    return _union;
}
function clamp(value, min, max) {
  return Math.max(min, Math.min(max, value));
}
function isBase64(str){
  if(str.indexOf('data:')!=-1 && str.indexOf('base64')!=-1 ){
      return true;
  }else{
      return false;
  }
}
function getSide(side){
let mapObject={front:"back",back:"front",none:"none"}
return mapObject[side]
}
export function isTypedArray(obj) {
    return obj instanceof ArrayBuffer ||
           obj instanceof Int8Array ||
           obj instanceof Uint8Array ||
           obj instanceof Uint8ClampedArray ||
           obj instanceof Int16Array ||
           obj instanceof Uint16Array ||
           obj instanceof Int32Array ||
           obj instanceof Uint32Array ||
           obj instanceof Float32Array ||
           obj instanceof Float64Array;
}
export const EXTENSION_FORMATS = {
    'texture-compression-bc': [
      'bc1-rgba-unorm',
      'bc1-rgba-unorm-srgb',
      'bc2-rgba-unorm',
      'bc2-rgba-unorm-srgb',
      'bc3-rgba-unorm',
      'bc3-rgba-unorm-srgb',
      'bc7-rgba-unorm',
      'bc7-rgba-unorm-srgb',
    ],
    'texture-compression-etc2': [
      "etc2-rgb8unorm",
      "etc2-rgb8unorm-srgb",
      "etc2-rgb8a1unorm",
      "etc2-rgb8a1unorm-srgb",
      "etc2-rgba8unorm",
      "etc2-rgba8unorm-srgb",
      "eac-r11unorm",
      "eac-r11snorm",
      "eac-rg11unorm",
      "eac-rg11snorm",
    ],
  };
export { stringHash, objectHash, guid, gIdColor, color2Id, asyncAll, mix,
    createElementNS, adjustCanvas,getDevicePixelRatio,getGPUType,getId,
    test,getEventPos,isNotBlank,randomString, buildFlatArray, checkTypedArrayType,isBlank, setUnion,clamp,isBase64,getSide,VertexFormat}
